#include "stdafx.h"
#include <future>

#include "FirefoxHandler.h"
#include "Server.h"
#include "JsScript.h"
#include "JsFunction.h"
#include "Cpu.h"
#include <assert.h>

using namespace std;

FirefoxHandler::FirefoxHandler()
{
    assert(_instance == nullptr);

    topObject = new QObject;
    auto cpu = Cpu::instance();
    Server::init(topObject);
    JsScriptManager::init(cpu);
    JsFunctionManager::init(cpu);

    _instance = this;
}

FirefoxHandler::~FirefoxHandler()
{
    delete topObject;
}

std::pair<bool, QString> FirefoxHandler::openTab(const QString &url, std::chrono::milliseconds timeout /*= _defaultTimeout*/)
{
    promise<QString> pro;
    auto onOpen = JsFunctionManager::port([&](QVariant args)
    {
        pro.set_value(args.toString());
    });


    JsScriptManager::runFunctionOnAddon("openTab", { url, onOpen });
    auto f = pro.get_future();
    if (f.wait_for(timeout) == future_status::ready)
    {
        return std::make_pair(true, f.get());
    }
    return std::make_pair(false, QString());
}

std::pair<bool, QVariant> FirefoxHandler::runScriptOnTab(const QString &tabstr, const QString &content, std::chrono::milliseconds timeout /*= _defaultTimeout*/)
{
    auto f = JsScriptManager::runOnTab(tabstr, content);
    if (f.wait_for(timeout) == future_status::ready)
    {
        auto retv = f.get();
        return std::make_pair(true, f.get());
    }
    return std::make_pair(false, QVariant());
}

std::pair<bool, QVariant> FirefoxHandler::runFunctionOnAddon(const QString &name, const QVariantList &args, std::chrono::milliseconds timeout /*= _defaultTimeout*/)
{
    auto f = JsScriptManager::runFunctionOnAddon(name, args);
    if (f.wait_for(timeout) == future_status::ready)
    {
        return std::make_pair(true, f.get());
    }
    return std::make_pair(false, QVariant());
}

std::pair<bool, QVariant> FirefoxHandler::runFunctionOnTab(const QString &tabstr, const QString &name, const QVariantList &args, std::chrono::milliseconds timeout /*= _defaultTimeout*/)
{
    auto f = JsScriptManager::runFunctionOnTab(tabstr, name, args);
    if (f.wait_for(timeout) == future_status::ready)
    {
        return std::make_pair(true, f.get());
    }
    return std::make_pair(false, QVariant());
}

std::chrono::milliseconds FirefoxHandler::operationTimeout()
{
    return _instance->_operationTimeout;
}

void FirefoxHandler::setOperationTimeout(const std::chrono::milliseconds &timeout)
{
    _instance->_operationTimeout = timeout;
}

bool FirefoxHandler::init()
{
    std::promise<bool> prom;
    std::thread([&]()
    {
        int argc = 0;
        char **argv = nullptr;
        QCoreApplication app(argc, argv);

        instance();
        prom.set_value(true);

        app.exec();
    }).detach();
    prom.get_future().wait();
    return Server::isListening();
}

FirefoxHandler * FirefoxHandler::instance()
{
    if (_instance == nullptr)
        _instance = new FirefoxHandler;
    return _instance;
}

FirefoxHandler * FirefoxHandler::_instance = nullptr;
